﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using IPC.Communication.Framework.BasicFramework;
using IPC.Communication.Framework.Core;
using IPC.Communication.Framework.Core.Address;

namespace IPC.Communication.Framework.Profinet.Melsec.Helper
{
    public class MelsecA3CNetHelper
    {
        public static byte[] PackCommand(IReadWriteA3C plc, byte[] mcCommand, byte station = 0)
        {
            MemoryStream memoryStream = new MemoryStream();
            if (plc.Format != 3)
            {
                memoryStream.WriteByte(5);
            }
            else
            {
                memoryStream.WriteByte(2);
            }
            if (plc.Format == 2)
            {
                memoryStream.WriteByte(48);
                memoryStream.WriteByte(48);
            }
            memoryStream.WriteByte(70);
            memoryStream.WriteByte(57);
            memoryStream.WriteByte(SoftBasic.BuildAsciiBytesFrom(station)[0]);
            memoryStream.WriteByte(SoftBasic.BuildAsciiBytesFrom(station)[1]);
            memoryStream.WriteByte(48);
            memoryStream.WriteByte(48);
            memoryStream.WriteByte(70);
            memoryStream.WriteByte(70);
            memoryStream.WriteByte(48);
            memoryStream.WriteByte(48);
            memoryStream.Write(mcCommand, 0, mcCommand.Length);
            if (plc.Format == 3)
            {
                memoryStream.WriteByte(3);
            }
            if (plc.SumCheck)
            {
                byte[] array = memoryStream.ToArray();
                int num = 0;
                for (int i = 1; i < array.Length; i++)
                {
                    num += array[i];
                }
                memoryStream.WriteByte(SoftBasic.BuildAsciiBytesFrom((byte)num)[0]);
                memoryStream.WriteByte(SoftBasic.BuildAsciiBytesFrom((byte)num)[1]);
            }
            if (plc.Format == 4)
            {
                memoryStream.WriteByte(13);
                memoryStream.WriteByte(10);
            }
            byte[] result = memoryStream.ToArray();
            memoryStream.Dispose();
            return result;
        }

        private static int GetErrorCodeOrDataStartIndex(IReadWriteA3C plc)
        {
            int result = 11;
            switch (plc.Format)
            {
                case 1:
                    result = 11;
                    break;
                case 2:
                    result = 13;
                    break;
                case 3:
                    result = 15;
                    break;
                case 4:
                    result = 11;
                    break;
            }
            return result;
        }

        public static OperateResult<byte[]> ExtraReadActualResponse(IReadWriteA3C plc, byte[] response)
        {
            try
            {
                int errorCodeOrDataStartIndex = GetErrorCodeOrDataStartIndex(plc);
                if (plc.Format == 1 || plc.Format == 2 || plc.Format == 4)
                {
                    if (response[0] == 21)
                    {
                        int num = Convert.ToInt32(Encoding.ASCII.GetString(response, errorCodeOrDataStartIndex, 4), 16);
                        return new OperateResult<byte[]>(num, MelsecHelper.GetErrorDescription(num));
                    }
                    if (response[0] != 2)
                    {
                        return new OperateResult<byte[]>(response[0], "Read Faild:" + SoftBasic.GetAsciiStringRender(response));
                    }
                }
                else if (plc.Format == 3)
                {
                    string @string = Encoding.ASCII.GetString(response, 11, 4);
                    if (@string == "QNAK")
                    {
                        int num2 = Convert.ToInt32(Encoding.ASCII.GetString(response, errorCodeOrDataStartIndex, 4), 16);
                        return new OperateResult<byte[]>(num2, MelsecHelper.GetErrorDescription(num2));
                    }
                    if (@string != "QACK")
                    {
                        return new OperateResult<byte[]>(response[0], "Read Faild:" + SoftBasic.GetAsciiStringRender(response));
                    }
                }
                int num3 = -1;
                for (int i = errorCodeOrDataStartIndex; i < response.Length; i++)
                {
                    if (response[i] == 3)
                    {
                        num3 = i;
                        break;
                    }
                }
                if (num3 == -1)
                {
                    num3 = response.Length;
                }
                return OperateResult.CreateSuccessResult(response.SelectMiddle(errorCodeOrDataStartIndex, num3 - errorCodeOrDataStartIndex));
            }
            catch (Exception ex)
            {
                return new OperateResult<byte[]>("ExtraReadActualResponse Wrong:" + ex.Message + Environment.NewLine + "Source: " + response.ToHexString(' '));
            }
        }

        private static OperateResult CheckWriteResponse(IReadWriteA3C plc, byte[] response)
        {
            int errorCodeOrDataStartIndex = GetErrorCodeOrDataStartIndex(plc);
            if (plc.Format == 1 || plc.Format == 2)
            {
                if (response[0] == 21)
                {
                    int num = Convert.ToInt32(Encoding.ASCII.GetString(response, errorCodeOrDataStartIndex, 4), 16);
                    return new OperateResult<byte[]>(num, MelsecHelper.GetErrorDescription(num));
                }
                if (response[0] != 6)
                {
                    return new OperateResult<byte[]>(response[0], "Write Faild:" + SoftBasic.GetAsciiStringRender(response));
                }
            }
            else if (plc.Format == 3)
            {
                if (response[0] != 2)
                {
                    return new OperateResult<byte[]>(response[0], "Write Faild:" + SoftBasic.GetAsciiStringRender(response));
                }
                string @string = Encoding.ASCII.GetString(response, 11, 4);
                if (@string == "QNAK")
                {
                    int num2 = Convert.ToInt32(Encoding.ASCII.GetString(response, errorCodeOrDataStartIndex, 4), 16);
                    return new OperateResult<byte[]>(num2, MelsecHelper.GetErrorDescription(num2));
                }
                if (@string != "QACK")
                {
                    return new OperateResult<byte[]>(response[0], "Write Faild:" + SoftBasic.GetAsciiStringRender(response));
                }
            }
            else if (plc.Format == 4)
            {
                if (response[0] == 21)
                {
                    int num3 = Convert.ToInt32(Encoding.ASCII.GetString(response, errorCodeOrDataStartIndex, 4), 16);
                    return new OperateResult<byte[]>(num3, MelsecHelper.GetErrorDescription(num3));
                }
                if (response[0] != 2)
                {
                    return new OperateResult<byte[]>(response[0], "Write Faild:" + SoftBasic.GetAsciiStringRender(response));
                }
            }
            return OperateResult.CreateSuccessResult();
        }

        public static OperateResult<byte[]> Read(IReadWriteA3C plc, string address, ushort length)
        {
            byte station = (byte)HslHelper.ExtractParameter(ref address, "s", plc.Station);
            OperateResult<McAddressData> operateResult = McAddressData.ParseMelsecFrom(address, length);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            byte[] mcCommand = McAsciiHelper.BuildAsciiReadMcCoreCommand(operateResult.Content, isBit: false);
            OperateResult<byte[]> operateResult2 = plc.ReadFromCoreServer(PackCommand(plc, mcCommand, station));
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            OperateResult<byte[]> operateResult3 = ExtraReadActualResponse(plc, operateResult2.Content);
            if (!operateResult3.IsSuccess)
            {
                return operateResult3;
            }
            return OperateResult.CreateSuccessResult(MelsecHelper.TransAsciiByteArrayToByteArray(operateResult3.Content));
        }

        //[AsyncStateMachine(typeof(<ReadAsync>d__5))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult<byte[]>> ReadAsync(IReadWriteA3C plc, string address, ushort length)
        //{
        //    <ReadAsync>d__5 stateMachine = new <ReadAsync>d__5();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
        //    stateMachine.plc = plc;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        public static OperateResult Write(IReadWriteA3C plc, string address, byte[] value)
        {
            byte station = (byte)HslHelper.ExtractParameter(ref address, "s", plc.Station);
            OperateResult<McAddressData> operateResult = McAddressData.ParseMelsecFrom(address, 0);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            byte[] mcCommand = McAsciiHelper.BuildAsciiWriteWordCoreCommand(operateResult.Content, value);
            OperateResult<byte[]> operateResult2 = plc.ReadFromCoreServer(PackCommand(plc, mcCommand, station));
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            return CheckWriteResponse(plc, operateResult2.Content);
        }

        //[AsyncStateMachine(typeof(<WriteAsync>d__7))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult> WriteAsync(IReadWriteA3C plc, string address, byte[] value)
        //{
        //    <WriteAsync>d__7 stateMachine = new <WriteAsync>d__7();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.plc = plc;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        public static OperateResult<bool[]> ReadBool(IReadWriteA3C plc, string address, ushort length)
        {
            byte station = (byte)HslHelper.ExtractParameter(ref address, "s", plc.Station);
            OperateResult<McAddressData> operateResult = McAddressData.ParseMelsecFrom(address, length);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult);
            }
            byte[] mcCommand = McAsciiHelper.BuildAsciiReadMcCoreCommand(operateResult.Content, isBit: true);
            OperateResult<byte[]> operateResult2 = plc.ReadFromCoreServer(PackCommand(plc, mcCommand, station));
            if (!operateResult2.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult2);
            }
            OperateResult<byte[]> operateResult3 = ExtraReadActualResponse(plc, operateResult2.Content);
            if (!operateResult3.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult3);
            }
            return OperateResult.CreateSuccessResult(operateResult3.Content.Select((byte m) => m == 49).ToArray());
        }

        //[AsyncStateMachine(typeof(<ReadBoolAsync>d__9))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult<bool[]>> ReadBoolAsync(IReadWriteA3C plc, string address, ushort length)
        //{
        //    <ReadBoolAsync>d__9 stateMachine = new <ReadBoolAsync>d__9();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<bool[]>>.Create();
        //    stateMachine.plc = plc;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        public static OperateResult Write(IReadWriteA3C plc, string address, bool[] value)
        {
            byte station = (byte)HslHelper.ExtractParameter(ref address, "s", plc.Station);
            OperateResult<McAddressData> operateResult = McAddressData.ParseMelsecFrom(address, 0);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult);
            }
            byte[] mcCommand = McAsciiHelper.BuildAsciiWriteBitCoreCommand(operateResult.Content, value);
            OperateResult<byte[]> operateResult2 = plc.ReadFromCoreServer(PackCommand(plc, mcCommand, station));
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            return CheckWriteResponse(plc, operateResult2.Content);
        }

        //[AsyncStateMachine(typeof(<WriteAsync>d__11))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult> WriteAsync(IReadWriteA3C plc, string address, bool[] value)
        //{
        //    <WriteAsync>d__11 stateMachine = new <WriteAsync>d__11();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.plc = plc;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        public static OperateResult RemoteRun(IReadWriteA3C plc)
        {
            OperateResult<byte[]> operateResult = plc.ReadFromCoreServer(PackCommand(plc, Encoding.ASCII.GetBytes("1001000000010000"), plc.Station));
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            return CheckWriteResponse(plc, operateResult.Content);
        }

        public static OperateResult RemoteStop(IReadWriteA3C plc)
        {
            OperateResult<byte[]> operateResult = plc.ReadFromCoreServer(PackCommand(plc, Encoding.ASCII.GetBytes("100200000001"), plc.Station));
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            return CheckWriteResponse(plc, operateResult.Content);
        }

        public static OperateResult<string> ReadPlcType(IReadWriteA3C plc)
        {
            OperateResult<byte[]> operateResult = plc.ReadFromCoreServer(PackCommand(plc, Encoding.ASCII.GetBytes("01010000"), plc.Station));
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<string>(operateResult);
            }
            OperateResult<byte[]> operateResult2 = ExtraReadActualResponse(plc, operateResult.Content);
            if (!operateResult2.IsSuccess)
            {
                return OperateResult.CreateFailedResult<string>(operateResult2);
            }
            return OperateResult.CreateSuccessResult(Encoding.ASCII.GetString(operateResult2.Content, 0, 16).TrimEnd());
        }

        //[AsyncStateMachine(typeof(<RemoteRunAsync>d__15))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult> RemoteRunAsync(IReadWriteA3C plc)
        //{
        //    <RemoteRunAsync>d__15 stateMachine = new <RemoteRunAsync>d__15();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.plc = plc;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<RemoteStopAsync>d__16))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult> RemoteStopAsync(IReadWriteA3C plc)
        //{
        //    <RemoteStopAsync>d__16 stateMachine = new <RemoteStopAsync>d__16();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.plc = plc;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<ReadPlcTypeAsync>d__17))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult<string>> ReadPlcTypeAsync(IReadWriteA3C plc)
        //{
        //    <ReadPlcTypeAsync>d__17 stateMachine = new <ReadPlcTypeAsync>d__17();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<string>>.Create();
        //    stateMachine.plc = plc;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}
    }
}
